package com.yalantis.ucrop.task;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.image.PixelMap;
import ohos.media.image.ImageSource;
import ohos.agp.utils.Matrix;
import ohos.media.image.common.Size;
import ohos.utils.net.Uri;
import com.yalantis.ucrop.util.LogUtils;

import com.yalantis.ucrop.callback.BitmapLoadCallback;
import com.yalantis.ucrop.model.ExifInfo;
import com.yalantis.ucrop.util.BitmapLoadUtils;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okio.BufferedSource;
import okio.Okio;
import okio.Sink;

import java.io.*;


/**
 * Creates and returns a Bitmap for a given Uri(String url).
 * inSampleSize is calculated based on requiredWidth property. However can be adjusted if OOM occurs.
 * If any EXIF config is found - bitmap is transformed properly.
 */
public class BitmapLoadTask {

    private static final String TAG = "BitmapWorkerTask";

    private static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024;   // 100 MB

    private final Context mContext;
    private Uri mInputUri;
    private final Uri mOutputUri;
    private final int mRequiredWidth;
    private final int mRequiredHeight;

    private final BitmapLoadCallback mBitmapLoadCallback;

    //原BitmapWorkerResult内的参数
    PixelMap mBitmapResult;
    ExifInfo mExifInfo;
    Exception mBitmapWorkerException;


    public BitmapLoadTask(Context context,
                           Uri inputUri,  Uri outputUri,
                          int requiredWidth, int requiredHeight,
                          BitmapLoadCallback loadCallback) {
        mContext = context;
        mInputUri = inputUri;
        mOutputUri = outputUri;
        mRequiredWidth = requiredWidth;
        mRequiredHeight = requiredHeight;
        mBitmapLoadCallback = loadCallback;
    }

    /**
     * 原AsyncTask的doInBackground
     */
    public void doInBackground(){
        EventRunner eventRunner = EventRunner.create();
        EventHandler handler = new EventHandler(eventRunner);
        handler.postTask(() -> {
            if (mInputUri == null) {
                mBitmapWorkerException = new NullPointerException("Input Uri cannot be null");
                mBitmapLoadCallback.onFailure(mBitmapWorkerException);
                return;
            }

            try {
                processInputUri();
            } catch (NullPointerException | IOException e) {
                mBitmapWorkerException = e;
                mBitmapLoadCallback.onFailure(mBitmapWorkerException);
                return;
            }
            //放在这里有用吗,移动到解码之后？
            final ImageSource.DecodingOptions options = new ImageSource.DecodingOptions();
//                options.sampleSize = BitmapLoadUtils.calculateInSampleSize(options, mRequiredWidth, mRequiredHeight);

            PixelMap decodeSampledBitmap = null;

            boolean decodeAttemptSuccess = false;
            while (!decodeAttemptSuccess) {
                try {
                    //通过InputUri获取InputStream
                    //InputStream stream = mContext.getContentResolver().openInputStream(mInputUri);
                    //通过InputUri获取InputStream
                    InputStream stream;
                    DataAbilityHelper helper = DataAbilityHelper.creator(mContext);
                    FileDescriptor fd = helper.openFile(mInputUri, "r");
                    stream = new FileInputStream(fd);
                    LogUtils.LogInfo("qqqqqq:",String.valueOf(mInputUri));
                    LogUtils.LogInfo("qqqqqq:",String.valueOf(stream));
//                        HttpURLConnection connection = null;
//                        URL url = new URL(String.valueOf(mInputUri));
//                        URLConnection urlConnection = url.openConnection();
//
//                        if (urlConnection instanceof HttpURLConnection) {
//                            connection = (HttpURLConnection) urlConnection;
//                        }
//                        if (connection != null) {
//                            connection.connect();
//                            // 之后可进行url的其他操作
//                            // 得到服务器返回过来的流对象
//                            stream = urlConnection.getInputStream();
//                        }
                    try {
                        ImageSource.SourceOptions sourceOptions = new ImageSource.SourceOptions();
                        ImageSource imageSource = ImageSource.create(stream,sourceOptions);
                        //一次读取获取原图大小
                        decodeSampledBitmap = imageSource.createPixelmap(options);
                        Size rawSize = decodeSampledBitmap.getImageInfo().size;
                        LogUtils.LogInfo("qqqqqq:","高"+rawSize.height +"宽"+ rawSize.width);
                        options.sampleSize = BitmapLoadUtils.calculateInSampleSize(rawSize, mRequiredWidth, mRequiredHeight);
                        options.desiredSize = new Size(rawSize.width / options.sampleSize, rawSize.height / options.sampleSize);
                        LogUtils.LogInfo("qqqqqq:","sample size"+ options.sampleSize);
                        //二次读取，获取缩放后的图像
                        decodeSampledBitmap = imageSource.createPixelmap(options);
                        if (decodeSampledBitmap==null) {
                            mBitmapWorkerException = new IllegalArgumentException("bitmap could not be retrieved from the Uri: [" + mInputUri + "]");
                            mBitmapLoadCallback.onFailure(mBitmapWorkerException);
                            return;

                        }
                    } finally {
                        BitmapLoadUtils.close(stream);
                    }
                    if (checkSize(decodeSampledBitmap, options)) continue;
                    decodeAttemptSuccess = true;
                } catch (OutOfMemoryError error) {
                    LogUtils.LogError(TAG, "doInBackground: BitmapFactory.decodeFileDescriptor: "+error);
                    options.sampleSize *= 2;
                } catch (IOException e) {
                    LogUtils.LogError(TAG, "doInBackground: ImageDecoder.createSource: "+e);
                    mBitmapWorkerException = new IllegalArgumentException("PixelMap could not be decoded from the Uri: [" + mInputUri + "]", e);
                    mBitmapLoadCallback.onFailure(mBitmapWorkerException);
                    return;
                } catch (DataAbilityRemoteException e) {
                    e.printStackTrace();
                } catch (RuntimeException e){
                    System.out.println();
                }
            }

            if (decodeSampledBitmap == null) {
                mBitmapWorkerException = new IllegalArgumentException("PixelMap could not be decoded from the Uri: [" + mInputUri + "]");
                mBitmapLoadCallback.onFailure(mBitmapWorkerException);
                return;
            }

            int exifOrientation = BitmapLoadUtils.getExifOrientation(mContext, mInputUri);
            int exifDegrees = BitmapLoadUtils.exifToDegrees(exifOrientation);
            int exifTranslation = BitmapLoadUtils.exifToTranslation(exifOrientation);

            ExifInfo exifInfo = new ExifInfo(exifOrientation, exifDegrees, exifTranslation);

            Matrix matrix = new Matrix();
            if (exifDegrees != 0) {
                matrix.preRotate(exifDegrees);
            }
            if (exifTranslation != 1) {
                matrix.postScale(exifTranslation, 1);
            }
            if (!matrix.isIdentity()) {
                BitmapLoadUtils bitmapLoadUtils = new BitmapLoadUtils();
                mBitmapResult = bitmapLoadUtils.transformBitmap(decodeSampledBitmap, exifDegrees, exifTranslation, mContext);
                mExifInfo = exifInfo;
                mBitmapLoadCallback.onBitmapLoaded(mBitmapResult, mExifInfo, mInputUri.getDecodedPath(), (mOutputUri == null) ? null : mOutputUri.getDecodedPath());
                return;
            }


            mBitmapResult = decodeSampledBitmap;
            LogUtils.LogInfo("qqqqqqqq:", String.valueOf(mBitmapResult.getImageInfo().size.height));
            mExifInfo = exifInfo;
            mBitmapLoadCallback.onBitmapLoaded(mBitmapResult, mExifInfo, mInputUri.getDecodedPath(), (mOutputUri == null) ? null : mOutputUri.getDecodedPath());
            LogUtils.LogInfo("qqqqqq:","main done");
        });

    }


    private void processInputUri() throws NullPointerException, IOException {
        if(mInputUri != null && mOutputUri != null) {
            String inputUriScheme = mInputUri.getScheme();
            if ("http".equals(inputUriScheme) || "https".equals(inputUriScheme)) {
               downloadFile(mInputUri, mOutputUri);
            } else if ("content".equals(inputUriScheme)) {
               copyFile(mInputUri, mOutputUri);
            } else if ("dataability".equals(inputUriScheme)) {
               copyFile(mInputUri, mOutputUri);
            } else if (!"file".equals(inputUriScheme)) {
                LogUtils.LogError(TAG, "Invalid Uri scheme " + inputUriScheme);
                throw new IllegalArgumentException("Invalid Uri scheme" + inputUriScheme);
            }
        }
    }

    private void copyFile(Uri inputUri,  Uri outputUri) throws IOException {
        LogUtils.LogDebug(TAG, "copyFile");
        System.out.println(inputUri);

        if (outputUri == null) {
            return;
        }

        InputStream inputStream;
        OutputStream outputStream;
        try {
            //通过InputUri获取InputStream
            //inputStream = mContext.getContentResolver().openInputStream(inputUri);
            //通过InputUri获取InputStream
            DataAbilityHelper helper = DataAbilityHelper.creator(mContext);
            if(helper != null) {
                FileDescriptor fd_i = helper.openFile(mInputUri, "r");
                if (fd_i != null) {
                    inputStream = new FileInputStream(fd_i);
                    FileDescriptor fd_o = helper.openFile(outputUri, "w");
                    if (fd_o != null) {
                        outputStream = new FileOutputStream(fd_o);

                        byte[] buffer = new byte[1024];
                        int length;
                        while ((length = inputStream.read(buffer)) > 0) {
                            outputStream.write(buffer, 0, length);
                        }
                    }
                }
            }
        } catch (DataAbilityRemoteException e) {
            e.printStackTrace();
        } finally {
            // swap uris, because input image was copied to the output destination
            // (cropped image will override it later)
            mInputUri = mOutputUri;
        }
    }

    private void downloadFile( Uri inputUri,  Uri outputUri) throws IOException {
        LogUtils.LogDebug(TAG, "downloadFile");

        if (outputUri == null) {
            return;
        }

        OkHttpClient client = new OkHttpClient();

        BufferedSource source = null;
        Sink sink;
        Response response = null;
        try {
            Request request = new Request.Builder()
                    .url(inputUri.toString())
                    .build();
            response = client.newCall(request).execute();
            assert response.body() != null;
            source = response.body().source();

            //通过OutputUri获取OutputStream
            //OutputStream outputStream = mContext.getContentResolver().openOutputStream(outputUri);
            //通过OutputUri获取OutputStream
            OutputStream outputStream;
            DataAbilityHelper helper = DataAbilityHelper.creator(mContext);
            if(helper != null) {
                FileDescriptor fd = helper.openFile(outputUri, "w");
                if (fd != null) {
                    outputStream = new FileOutputStream(fd);
                    if (outputStream != null) {
                        sink = Okio.sink(outputStream);
                        source.readAll(sink);
                    } else {
                    }
                }
            }
        } catch (DataAbilityRemoteException e) {
            e.printStackTrace();
        } finally {
            BitmapLoadUtils.close(source);
            if (response != null) {
                BitmapLoadUtils.close(response.body());
            }
            client.dispatcher().cancelAll();

            // swap uris, because input image was downloaded to the output destination
            // (cropped image will override it later)
            mInputUri = mOutputUri;
        }
    }


    private boolean checkSize(PixelMap bitmap, ImageSource.DecodingOptions options) {
        long bitmapSize = bitmap != null ? bitmap.getPixelBytesNumber() : 0;
        if (bitmapSize > MAX_BITMAP_SIZE) {
            options.sampleSize *= 2;
            return true;
        }
        return false;
    }
}
